package service

import (
	"fmt"
	"time"

	"gitee.com/openeuler/PilotGo/sdk/logger"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/internal/global"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/pkg/utils"
)

type JobStatCache struct {
	JobId       string    `json:"job_id"`
	TotalHosts  int       `json:"total_hosts"`
	UpdateHosts int       `json:"update_hosts"`
	UpdateTime  time.Time `json:"update_time"`
}

func generateJobCacheKey(jobId string) string {
	return fmt.Sprintf("jobs:%s", jobId)
}

func lockJobKey(jobId string) string {
	return fmt.Sprintf("lock:job:%s", jobId)
}

func SetJobCache(jobId string, totalHosts, updateHosts int) error {
	lockKey := lockJobKey(jobId)
	lockValue := utils.GenerateUUID()
	if err := global.App.Redis.AcquireLockWithRetry(lockKey, lockValue, 30*time.Second, 100*time.Millisecond, 5*time.Second); err != nil {
		return fmt.Errorf("获取作业锁失败: %s", err.Error())
	}
	defer func() {
		if err := global.App.Redis.ReleaseLock(lockKey, lockValue); err != nil {
			logger.Error("释放作业锁失败: %v", err)
		}
	}()

	cache := &JobStatCache{
		JobId:       jobId,
		TotalHosts:  totalHosts,
		UpdateHosts: updateHosts,
		UpdateTime:  time.Now(),
	}
	if err := global.App.Redis.SetNX(generateJobCacheKey(jobId), cache, -1); err != nil {
		return fmt.Errorf("设置作业缓存失败: %w", err)
	}
	return nil
}

func GetJobCache(jobId string) (*JobStatCache, error) {
	var cache JobStatCache
	if err := global.App.Redis.Get(generateJobCacheKey(jobId), &cache); err != nil {
		return nil, err
	}
	return &cache, nil
}

func DeleteJobCache(jobId string) error {
	lockKey := lockJobKey(jobId)
	lockValue := utils.GenerateUUID()
	if err := global.App.Redis.AcquireLockWithRetry(lockKey, lockValue, 30*time.Second, 100*time.Millisecond, 5*time.Second); err != nil {
		return fmt.Errorf("获取作业锁失败: %s", err.Error())
	}
	defer func() {
		if err := global.App.Redis.ReleaseLock(lockKey, lockValue); err != nil {
			logger.Warn("释放作业锁失败: %v", err)
		}
	}()

	if err := global.App.Redis.Delete(generateJobCacheKey(jobId)); err != nil {
		return err
	}

	return nil
}

func UpdateJobCache(jobId string) error {
	lockKey := lockJobKey(jobId)
	lockValue := utils.GenerateUUID()
	if err := global.App.Redis.AcquireLockWithRetry(lockKey, lockValue, 30*time.Second, 100*time.Millisecond, 5*time.Second); err != nil {
		return fmt.Errorf("获取作业锁失败: %s", err.Error())
	}
	defer func() {
		if err := global.App.Redis.ReleaseLock(lockKey, lockValue); err != nil {
			logger.Warn("释放作业锁失败: %v", err)
		}
	}()

	state, err := GetJobCache(jobId)
	if err != nil {
		return fmt.Errorf("获取作业整体信息失败: %s", err.Error())
	}
	cache := &JobStatCache{
		JobId:       jobId,
		TotalHosts:  state.TotalHosts,
		UpdateHosts: state.UpdateHosts + 1,
		UpdateTime:  time.Now(),
	}

	if err := global.App.Redis.Set(generateJobCacheKey(jobId), cache, -1); err != nil {
		return err
	}
	if state.UpdateHosts >= ThresholdHosts(state.TotalHosts) {
		select {
		case jobResultUpdateChan <- jobId:
			logger.Debug("触发父作业更新: jobId=%s", jobId)
		default:
			logger.Warn("父作业更新通道已满: jobId=%s", jobId)
		}
	}
	return nil
}

// 阈值函数，可动态调整
func ThresholdHosts(total int) int {
	if total <= 10 {
		return 1
	}
	return total / 10
}
